package com.lottery.system.service.impl;
import com.lottery.system.common.errorcode.ServiceErrorCodeConstants;
import com.lottery.system.common.exception.ServiceException;
import com.lottery.system.common.utils.JwtUtil;
import com.lottery.system.common.utils.RegexUtil;
import com.lottery.system.common.utils.SecretUtil;
import com.lottery.system.controller.param.UserLoginBaseParam;
import com.lottery.system.controller.param.UserLoginByCaptchaParam;
import com.lottery.system.controller.param.UserLoginByPasswordParam;
import com.lottery.system.controller.param.UserRegisterParam;
import com.lottery.system.dao.dataobject.Encrypt;
import com.lottery.system.dao.dataobject.UserDo;
import com.lottery.system.dao.mapper.UserMapper;
import com.lottery.system.service.UserService;
import com.lottery.system.service.VerificationCodeService;
import com.lottery.system.service.dto.UserDTO;
import com.lottery.system.service.dto.UserLoginDTO;
import com.lottery.system.service.dto.UserRegisterDto;
import com.lottery.system.service.enums.IdentifyEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: xiaoxie
 * create: 2024-09-02 21:39
 * @BelongsProject: lottery-system
 * @BelongsPackage: com.lottery.system.service.impl
 * description: 用户的业务逻辑层接口的实现类
 */
@Service
public class UserServiceImpl implements UserService {
    //日志
    private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private VerificationCodeService verificationCodeService;
    /**
     * @description: 用户注册
     * @author: xiaoxie
     * @date: 2024/9/2 21:40
     * @param: [param]
     * @return: com.lottery.system.service.dto.UserRegisterDto
     **/
    @Override
    public UserRegisterDto register(UserRegisterParam param) {
        //校验接收的参数不能为空
        if(null == param) {
            logger.error(ServiceErrorCodeConstants.USER_INFO_EMPTY.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_EMPTY);
        }
        //校验数据
        checkParam(param);
        //数据处理
        UserDo userDo = processingParam(param);
        //保存数据
        userMapper.insert(userDo);
        UserRegisterDto userRegisterDto = new UserRegisterDto();
        userRegisterDto.setUserId(userDo.getId());
        //返回结果
        return userRegisterDto;
    }

    /**
     * @description: 用户登录
     * @author: xiaoxie
     * @date: 2024/9/5 17:39
     * @param: [param]
     * @return: com.lottery.system.service.dto.UserLoginDTO
     **/
    @Override
    public UserLoginDTO login(UserLoginBaseParam param) {
        //首先需要判断一下是通过什么方式登录 1.密码 2.验证码
        UserLoginDTO userLoginDTO;
        if(param instanceof UserLoginByPasswordParam loginParam) {
            //密码登录
            userLoginDTO =loginByPassword(loginParam);
        } else if (param instanceof UserLoginByCaptchaParam loginParam) {
            //验证码登录
            userLoginDTO =loginByCaptcha(loginParam);
        }else {
            logger.error(ServiceErrorCodeConstants.LOGIN_INFO_IS_EXIST.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_IS_EXIST);
        }
        //返回
        return userLoginDTO;
       
    }

    /**
     * @description: 获取人员列表
     * @author: xiaoxie
     * @date: 2024/9/6 11:05
     * @param: [identity]
     * @return: java.util.List<com.lottery.system.service.dto.UserDTO>
     **/
    @Override
    public List<UserDTO> getListByIdentify(IdentifyEnum identity) {
        //判断身份信息是否为空.
        String identify = identity == null ? null : identity.name();
        //查表
        List<UserDo> userDoList = userMapper.getUserInfoByIdentify(identify);
        if(userDoList == null || userDoList.isEmpty()) {
            return Collections.emptyList();
        }
        //类型转换
     return userDoList.stream()
                .map(userDO -> {
                    UserDTO userDTO = new UserDTO();
                    userDTO.setUserId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEmail(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentify(IdentifyEnum.forName(userDO.getIdentify()));
                    return userDTO;
                }).toList();
    }

    /**
     * @description: 验证码登录
     * @author: xiaoxie
     * @date: 2024/9/5 12:47
     * @param: [loginParam]
     * @return: com.lottery.system.service.dto.UserLoginDTO
     **/
    private UserLoginDTO loginByCaptcha(UserLoginByCaptchaParam loginParam) {
        //1.校验手机号码是否格式正确
        if(!RegexUtil.checkMobile(loginParam.getPhoneNumber())) {
            logger.error(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //查表
        UserDo userDo = userMapper.userInfoByPhone(new Encrypt(loginParam.getPhoneNumber()));
        // 2.登录身份
        if(null == userDo) {
            logger.error(ServiceErrorCodeConstants.USER_INFO_IS_EXIST.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EXIST);
        } else if (StringUtils.hasText(loginParam.getIdentify())
                    &&!loginParam.getIdentify().equalsIgnoreCase(userDo.getIdentify())) {
            logger.error(ServiceErrorCodeConstants.IDENTIFY_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.IDENTIFY_ERROR);
        }
       // 3.验证码是否正确
        String code =  verificationCodeService.getVerificationCode(loginParam.getPhoneNumber());
        if(null == code) {
            logger.error(ServiceErrorCodeConstants.CAPTCHA_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.CAPTCHA_ERROR);
        } else if (!code.equals(loginParam.getCode())) {
            logger.error(ServiceErrorCodeConstants.CAPTCHA_IS_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.CAPTCHA_IS_ERROR);
        }
        //生成Token令牌
        return createToken(userDo);
    }

    /**
     * @description: 通过密码登录
     * @author: xiaoxie
     * @date: 2024/9/5 17:39
     * @param: [loginParam]
     * @return: com.lottery.system.service.dto.UserLoginDTO
     **/
    private UserLoginDTO loginByPassword(UserLoginByPasswordParam loginParam) {
        //1.校验手机号码或者邮箱格式是否正确
        UserDo userDo;
        if(RegexUtil.checkMobile(loginParam.getLoginName())) {
            //根据手机号进行查表
            userDo = userMapper.userInfoByPhone(new Encrypt(loginParam.getLoginName()));
        } else if (RegexUtil.checkMail(loginParam.getLoginName())) {
            //根据邮箱进行查表
            userDo = userMapper.userInfoByEmail(loginParam.getLoginName());
        }else {
            logger.error(ServiceErrorCodeConstants.LOGIN_INFO_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_ERROR);
        }
        //2.登录身份 密码是否正确
        if(null == userDo) {
            logger.error(ServiceErrorCodeConstants.USER_INFO_IS_EXIST.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EXIST);
        } else if (StringUtils.hasText(loginParam.getIdentify())
                &&!loginParam.getIdentify().equalsIgnoreCase(userDo.getIdentify())) {
            logger.error(ServiceErrorCodeConstants.IDENTIFY_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.IDENTIFY_ERROR);
        } else if(!SecretUtil.verify(loginParam.getPassword(),userDo.getSalt(),userDo.getPassword())) {
            logger.error(ServiceErrorCodeConstants.PASSWORD_IS_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_ERROR);
        }
        //生成Token令牌
        return createToken(userDo);
    }

    /**
     * @description: 生成Token令牌
     * @author: xiaoxie
     * @date: 2024/9/5 17:39
     * @param: [userDo]
     * @return: com.lottery.system.service.dto.UserLoginDTO
     **/
    private UserLoginDTO createToken(UserDo userDo) {
        Map<String,Object> claim = new HashMap<>();
        claim.put("userId",userDo.getId());
        claim.put("identify",userDo.getIdentify());
        String token = JwtUtil.generateToken(claim);
        //构造返回对象
        UserLoginDTO loginDTO = new UserLoginDTO();
        loginDTO.setToken(token);
        loginDTO.setIdentify(IdentifyEnum.forName(userDo.getIdentify()));
        return loginDTO;
    }


    /**
     * @description: 处理加密参数
     * @author: xiaoxie
     * @date: 2024/9/3 11:12
     * @param: [param]
     * @return: void
     **/
    private UserDo processingParam(UserRegisterParam param) {
        UserDo userDo = new UserDo();
        userDo.setUserName(param.getUserName());
        userDo.setEmail(param.getEmail());
        userDo.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDo.setIdentify(param.getIdentify());
        if(Objects.equals(IdentifyEnum.forName(param.getIdentify()), IdentifyEnum.ADMIN)) {
            String salt = SecretUtil.getSalt();
            userDo.setSalt(salt);
            userDo.setPassword(SecretUtil.passwordAndSaltByMd5(param.getPassword(), salt));
        }
        return userDo;
    }
    /**
     * @description: 校验注册的参数
     * @author: xiaoxie
     * @date: 2024/9/5 17:33
     * @param: [param]
     * @return: void
     **/

    private void checkParam(UserRegisterParam param) {
        //校验必需的数据是否为空
        if(!StringUtils.hasLength(param.getUserName())
                || !StringUtils.hasLength(param.getPhoneNumber())
                || !StringUtils.hasLength(param.getEmail())
                || !StringUtils.hasLength(param.getIdentify())) {
            logger.error(ServiceErrorCodeConstants.USER_DATA_EMPTY.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_DATA_EMPTY);
        }
        //校验用户名,用户在数据库中不存在
        if(checkUsername(param.getUserName())) {
            logger.error(ServiceErrorCodeConstants.USERNAME_USED.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USERNAME_USED);
        }
        //校验邮箱,格式正确,在数据库中不存在
        if(checkEmail(param.getEmail()) && !RegexUtil.checkMail(param.getEmail())) {
            logger.error(ServiceErrorCodeConstants.EMAIL_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.EMAIL_ERROR);
        }
        //校验电话号码,格式正确,在数据库中不存在
        if(checkPhone(param.getPhoneNumber()) && !RegexUtil.checkMobile(param.getPhoneNumber())) {
            logger.error(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //校验身份信息
        if(!Objects.equals(IdentifyEnum.forName(param.getIdentify()), IdentifyEnum.ADMIN)
                &&!Objects.equals(IdentifyEnum.forName(param.getIdentify()), IdentifyEnum.NORMAL)) {
            logger.error(ServiceErrorCodeConstants.IDENTIFY_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.IDENTIFY_ERROR);
        }

        //校验如果为管理员,密码和确认密码不能为空,格式正确.
        if(Objects.equals(IdentifyEnum.forName(param.getIdentify()), IdentifyEnum.ADMIN)) {
            if(!StringUtils.hasLength(param.getPassword()) || !StringUtils.hasLength(param.getRePassword())) {
                logger.error(ServiceErrorCodeConstants.USER_DATA_EMPTY.getMsg());
                throw new ServiceException(ServiceErrorCodeConstants.USER_DATA_EMPTY);
            }
            checkPassword(param.getPassword(),param.getRePassword());
        }
    }

   /**
    * @description: 校验密码和确认密码的是否正确
    * @author: xiaoxie
    * @date: 2024/9/3 11:11
    * @param: [password, rePassword]
    * @return: void
    **/
    private void checkPassword(String password, String rePassword) {
        if(!RegexUtil.checkPassword(password) || !RegexUtil.checkPassword(rePassword)) {
            logger.error(ServiceErrorCodeConstants.PASSWORD_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        if(!password.equals(rePassword)) {
            logger.error(ServiceErrorCodeConstants.PASSWORD_REPASSWORD_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_REPASSWORD_ERROR);
        }
    }

    /**
     * @description: 校验电话号码是否存在
     * @author: xiaoxie
     * @date: 2024/9/2 22:28
     * @param: [userName]
     * @return: boolean
     **/

    private boolean checkPhone(String phone) {
        int count = userMapper.phoneUsed(new Encrypt(phone));
        if(count > 0) {
            logger.error(ServiceErrorCodeConstants.PHONE_NUMBER_USED.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
        return true;
    }

    /**
     * @description: 校验邮箱是否存在
     * @author: xiaoxie
     * @date: 2024/9/2 22:28
     * @param: [userName]
     * @return: boolean
     **/

    private boolean checkEmail(String email) {
        int count = userMapper.emailUsed(email);
        if(count > 0) {
            logger.error(ServiceErrorCodeConstants.EMAIL_USED.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.EMAIL_USED);
        }
        return true;
    }

    /**
     * @description: 校验用户名是否存在
     * @author: xiaoxie
     * @date: 2024/9/2 22:28
     * @param: [userName]
     * @return: boolean
     **/
    private boolean checkUsername(String userName) {
        int count = userMapper.userNameUsed(userName);
        logger.info("count: {}", count);
        return count > 0;
    }
}
